package org.wxy.sdk.util;

import android.content.Context;
import android.support.annotation.NonNull;

import org.wxy.sdk.Constants;
import org.wxy.sdk.base.BeanObject;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
 * Created by wxy on 2018/05/27.
 *
 * @author wxy
 * @date on 2018/05/27 11:32
 */
public class FileCache {

    private static final String IMAGE_CACHE = "imageCache";
    private static final String AUDIO_CACHE = "audioCache";
    private static final String VIDEO_CACHE = "videoCache";
    private static final String HTTP_CACHE = "httpCache";
    private static File sImageCacheDir;
    private static File sAudioCacheDir;
    private static File sVideoCacheDir;
    private static File sHttpCacheDir;

    public static void initCache(Context context) {
        sImageCacheDir = new File(context.getExternalCacheDir(), IMAGE_CACHE);
        sAudioCacheDir = new File(context.getExternalCacheDir(), AUDIO_CACHE);
        sVideoCacheDir = new File(context.getExternalCacheDir(), VIDEO_CACHE);
        sHttpCacheDir = new File(context.getExternalCacheDir(), HTTP_CACHE);
        if (!sImageCacheDir.exists()) {
            sImageCacheDir.mkdirs();
        }

        if (!sAudioCacheDir.exists()) {
            sAudioCacheDir.mkdirs();
        }

        if (!sVideoCacheDir.exists()) {
            sVideoCacheDir.mkdirs();
        }

        if (!sHttpCacheDir.exists()) {
            sHttpCacheDir.mkdirs();
        }
    }

    public static File getImageCacheDir(Context context) {
        if (sImageCacheDir == null) {
            sImageCacheDir = new File(context.getExternalCacheDir(), IMAGE_CACHE);

            if (!sImageCacheDir.exists()) {
                sImageCacheDir.mkdirs();
            }
        }
        return sImageCacheDir;
    }

    public static String getImageCache(Context context, String url) {
        File file = new File(getImageCacheDir(context), getCacheName(url));
        return file.getAbsolutePath();
    }

    public static boolean isImageExist(Context context, String fileName) {
        File file = new File(getImageCacheDir(context), fileName);
        return file.exists();
    }

    public static String getCacheName(String url) {
        return MD5.stringToMD5(url);
    }

    /**
     * 下载文件
     * @param url
     */
    public static void downloadImage(Context context, final String url, @NonNull final OnDownloadListener listener) {
        File file = new File(getImageCacheDir(context), getCacheName(url));
        Observable.just(file)
                .map(new Func1<File, File>() {
                    @Override
                    public File call(File file) {
                        try {

                            URL httpUrl = new URL(url);

                            InputStream in = httpUrl.openStream();

                            byte[] buffer = new byte[4*1024];

                            FileOutputStream fos = new FileOutputStream(file);
                            int len;
                            while((len = in.read(buffer)) != -1) {
                                fos.write(buffer, 0, len);
                            }
                            in.close();
                            fos.close();
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                        return file;
                    }
                })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<File>() {
                    @Override
                    public void call(File file) {
                        listener.onSuccess(file);
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        listener.onError(throwable);
                    }
                });
    }

    public static long cacheSize(Context context) {
        return fileSize(context.getExternalCacheDir());
    }

    private static long fileSize(File file) {
        if (file.isFile()) {
            return file.length();
        } else {
            long size = 0;
            File[] files = file.listFiles();
            for (File f : files) {
                size += fileSize(f);
            }
            return size;
        }
    }

    public static File getAudioCacheDir(Context context) {
        if (sAudioCacheDir == null) {
            sAudioCacheDir = new File(context.getExternalCacheDir(), AUDIO_CACHE);
            if (!sAudioCacheDir.exists()) {
                sAudioCacheDir.mkdirs();
            }
        }
        return sAudioCacheDir;
    }

    public static File getVideoCacheDir(Context context) {
        if (sVideoCacheDir == null) {
            sVideoCacheDir = new File(context.getExternalCacheDir(), AUDIO_CACHE);
            if (!sVideoCacheDir.exists()) {
                sVideoCacheDir.mkdirs();
            }
        }
        return sVideoCacheDir;
    }

    public static <T extends BeanObject> void saveObject(T t) {
        File file = new File(sHttpCacheDir, t.getClass().getName());

        try {
            FileOutputStream fos = new FileOutputStream(file);

            fos.write(Constants.json().toJson(t).getBytes("UTF-8"));

            fos.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T extends BeanObject> T getObject(Class<T> tClass) {
        File file = new File(sHttpCacheDir, tClass.getName());
        try {
            FileInputStream fis = new FileInputStream(file);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            int len = 0;
            byte[] buffer = new byte[4*1024];

            while((len = fis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            fis.close();
            return Constants.json().toJava(new String(bos.toByteArray(), "UTF-8"), tClass);
        } catch (Exception e) {
            AppLog.e(e.getMessage(), e);
            return null;
        }
    }

    public interface OnDownloadListener {
        /**
         * Fired when a compression returns successfully, override to handle in your own code
         */
        void onSuccess(File file);

        /**
         * Fired when a compression fails to complete, override to handle in your own code
         */
        void onError(Throwable e);
    }
}
